package fuzion24.device.vulnerability.vulnerabilities.framework.media;

import android.content.Context;
import android.os.Build;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;

import fuzion24.device.vulnerability.util.CPUArch;
import fuzion24.device.vulnerability.vulnerabilities.VulnerabilityTest;
import fuzion24.device.vulnerability.vulnerabilities.helper.BinaryAssets;
import fuzion24.device.vulnerability.vulnerabilities.helper.KMPMatch;
import fuzion24.device.vulnerability.vulnerabilities.helper.SystemUtils;

/**
 * Created by fuzion24 on 11/16/15.
 */


/*
https://android.googlesource.com/platform/external/tremolo/+/3830d0b585ada64ee75dea6da267505b19c622fd%5E%21/#F1
https://android.googlesource.com/platform/frameworks/av/+/c6a2815eadfce62702d58b3fa3887f24c49e1864%5E%21/#F0

2|shell@flounder_lte:/ $ grep -F "b/23881715" /system/lib/libstagefright.so
1|shell@flounder_lte:/ $ grep -F "b/23881715" /system/lib64/libstagefright.so
*/

public class CVE_2015_6608 implements VulnerabilityTest {

    private static final String TAG = "CVE-2015-6608";

    @Override
    public String getCVEorID() {
        return "CVE-2015-6608";
    }

    @Override
    public boolean isVulnerable(Context context) throws Exception {
        /*
            The patch includes logging messages for when the vulnerable code paths are hit.
            We can simply look for the inclusion of the strings in the libraries to determine
            whether or not the device has a patched libstagefright.so
         */

        File stagefrightlib = new File("/system/lib/libstagefright.so");
        File stagefrightlib64 = new File("/system/lib64/libstagefright.so");

        File softAAClib = new File("/system/lib/libstagefright_soft_aacdec.so");

        File libvorbisidec = new File("/system/lib/libvorbisidec.so");

        if(!stagefrightlib.exists() || !stagefrightlib.isFile()){
            throw new Exception("libstagefright.so doesn't exist or is not a file");
        }

        if(!softAAClib.exists()){
            throw new Exception("libstagefright_soft_aacdec.so does not exist");
        }

        if(!libvorbisidec.exists()){
            throw new Exception("libvorbisidec.so does not exist");
        }


        ByteArrayOutputStream libStageFrightBAOS = new ByteArrayOutputStream((int)stagefrightlib.length());
        BinaryAssets.copy(new FileInputStream(stagefrightlib), libStageFrightBAOS);
        byte[] libstagefrightSO = libStageFrightBAOS.toByteArray();


        ByteArrayOutputStream libaacdecBAOS = new ByteArrayOutputStream((int)softAAClib.length());
        BinaryAssets.copy(new FileInputStream(softAAClib), libaacdecBAOS);
        byte[] libaacdecSO = libaacdecBAOS.toByteArray();

        ByteArrayOutputStream libvorbisidecBAOS = new ByteArrayOutputStream((int)libvorbisidec.length());
        BinaryAssets.copy(new FileInputStream(libvorbisidec), libvorbisidecBAOS);
        byte[] libvorbisidecSO = libvorbisidecBAOS.toByteArray();



        KMPMatch binMatcher = new KMPMatch();

        int indexOf = binMatcher.indexOf(libstagefrightSO, "b/23680780".getBytes());
        boolean libstagefrightVulnerableToBug23680780 = indexOf == -1;
        indexOf = binMatcher.indexOf(libvorbisidecSO, "b/23881715".getBytes());
        boolean libstagefrightvulnerableToBug23881715 = indexOf == -1;
        indexOf = binMatcher.indexOf(libaacdecSO, "b/23876444".getBytes());
        boolean libstagefrightVulnerableToBug23876444 = indexOf == -1;


        Log.d(TAG, "libstagefrightVulnerableToBug23680780: " + libstagefrightVulnerableToBug23680780);
        Log.d(TAG, "libsatagefrightvulnerableToBug23881715: " + libstagefrightvulnerableToBug23881715);
        Log.d(TAG, "libstagefrightVulnerableToBug23876444: " + libstagefrightVulnerableToBug23876444);

        if(Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT){
            return libstagefrightvulnerableToBug23881715;
        }

        //The rest only affect L and M
        if     (Build.VERSION.SDK_INT != Build.VERSION_CODES.M &&
                Build.VERSION.SDK_INT != Build.VERSION_CODES.LOLLIPOP &&
                Build.VERSION.SDK_INT != Build.VERSION_CODES.LOLLIPOP_MR1){
            return false;
        }

        return  libstagefrightVulnerableToBug23680780 ||
                libstagefrightvulnerableToBug23881715 ||
                libstagefrightVulnerableToBug23876444;

    }

    @Override
    public List<CPUArch> getSupportedArchitectures() {
        List<CPUArch> supportedArchs = new ArrayList<>();
        supportedArchs.add(CPUArch.ARM);
        supportedArchs.add(CPUArch.ARM7);
        supportedArchs.add(CPUArch.ARM8);
        supportedArchs.add(CPUArch.X86);
        return supportedArchs;
    }
}
